﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Bymed.SpineScan.DataModel;
using Bymed.SpineScan.DataModel.TestItem;

namespace Bymed.SpineScan.Service
{
    public static class TestItemFactory
    {
        public const char MessageContentSeparator = '|';
        private static ScoliosisATITest _scoliosisATITest;
        private static string _graphMessagePattern = @"\d+\s+a=\s?(?<Result>-?.+)";
        private static string _graphRawData = string.Empty;

        public static TestItemBase GetTestItem(string testMessage)
        {
            TestItemBase testItem = null;
            testMessage = testMessage.TrimEnd();
            var testMessageLower = testMessage.ToLower();

            if (IsMatchAtiMessage(testMessageLower) && !IsMatchAtiGraphMessage(testMessageLower))
            {
                _scoliosisATITest = new ScoliosisATITest(testMessage);
                testItem = _scoliosisATITest;
            }
            else if (IsMatchKyphosisMessage(testMessageLower))
            {
                testItem = new KyphosisTest(testMessage);
            }
            else if (IsMatchFlexMessage(testMessageLower))
            {
                testItem = new FlexionExtensionTest(testMessage);
            }
            else if (IsMatchLateralMessage(testMessageLower))
            {
                testItem = new LateralBendingTest(testMessage);
            }
            else if (IsMatchRotationMessage(testMessageLower))
            {
                testItem = new RotationTest(testMessage);
            }
            else if (IsMatchBalanceMessage(testMessageLower))
            {
                testItem = new BalanceTest(testMessage);
            }
            else if (CheckGraphData(testMessage))
            {
                AddGraphData(testMessage);
                testItem = _scoliosisATITest;
            }

            return testItem;
        }

        /// <summary>
        /// Check whether current test message is indicating the graph data.
        /// </summary>
        /// <param name="testMessage">The test message comes from device.</param>
        /// <returns>True means this test message is indicating the graph data. False means NOT.</returns>
        public static bool CheckGraphData(string testMessage)
        {
            var regex = new Regex(_graphMessagePattern, RegexOptions.IgnoreCase);
            return regex.IsMatch(testMessage);
        }

        /// <summary>
        /// Convert the provided graph raw data which in string formatGenerate to IList based graph data.
        /// </summary>
        /// <param name="graphRawData">Graph raw data in string format</param>
        /// <returns>IList based graph data.</returns>
        public static IList<double> ConvertGraphRawData(string graphRawData)
        {
            var graphDataArray = graphRawData.Split(MessageContentSeparator);
            var graphDataList = new List<double>();

            foreach (var graphData in graphDataArray)
            {
                graphDataList.Add(double.Parse(graphData));
            }

            return graphDataList;
        }

        /// <summary>
        /// Add matched graph data. For ScoliosisATITest ONLY.
        /// </summary>
        /// <param name="testMessage">The test message comes from device.</param>
        private static void AddGraphData(string testMessage)
        {
            var regex = new Regex(_graphMessagePattern, RegexOptions.IgnoreCase);
            var matches = regex.Matches(testMessage);

            if (matches.Count > 0)
            {
                _scoliosisATITest.Graph.Add(double.Parse(matches[0].Groups["Result"].Value));
            }
        }

        /// <summary>
        /// Check if the provided test message matches ati test type.
        /// </summary>
        /// <param name="testMessage">The provided test message.</param>
        /// <returns>True means matched. False means NOT matched.</returns>
        private static bool IsMatchAtiMessage(string testMessage)
        {
            return testMessage.StartsWith("ati") ? true : false;
        }

        /// <summary>
        /// Check if the provided test message matches ati graph test type.
        /// </summary>
        /// <param name="testMessage">The provided test message.</param>
        /// <returns>True means matched. False means NOT matched.</returns>
        private static bool IsMatchAtiGraphMessage(string testMessage)
        {
            return testMessage.StartsWith("ati graph") ? true : false;
        }

        /// <summary>
        /// Check if the provided test message matches kyphosis test type.
        /// </summary>
        /// <param name="testMessage">The provided test message.</param>
        /// <returns>True means matched. False means NOT matched.</returns>
        private static bool IsMatchKyphosisMessage(string testMessage)
        {
            return testMessage.StartsWith("kyphosis") ? true : false;
        }

        /// <summary>
        /// Check if the provided test message matches flex test type.
        /// </summary>
        /// <param name="testMessage">The provided test message.</param>
        /// <returns>True means matched. False means NOT matched.</returns>
        private static bool IsMatchFlexMessage(string testMessage)
        {
            return testMessage.StartsWith("flex") ? true : false;
        }

        /// <summary>
        /// Check if the provided test message matches lateral test type.
        /// </summary>
        /// <param name="testMessage">The provided test message.</param>
        /// <returns>True means matched. False means NOT matched.</returns>
        private static bool IsMatchLateralMessage(string testMessage)
        {
            return testMessage.StartsWith("lateral") ? true : false;
        }

        /// <summary>
        /// Check if the provided test message matches rotation test type.
        /// </summary>
        /// <param name="testMessage">The provided test message.</param>
        /// <returns>True means matched. False means NOT matched.</returns>
        private static bool IsMatchRotationMessage(string testMessage)
        {
            return testMessage.StartsWith("rotation") ? true : false;
        }

        /// <summary>
        /// Check if the provided test message matches balance test type.
        /// </summary>
        /// <param name="testMessage">The provided test message.</param>
        /// <returns>True means matched. False means NOT matched.</returns>
        private static bool IsMatchBalanceMessage(string testMessage)
        {
            return testMessage.StartsWith("balance") ? true : false;
        }
    }
}
